package com.neuronbit.businessflow.flow.source.util;

import com.neuronbit.businessflow.flow.clazz.SourceType;
import com.neuronbit.businessflow.intellij.model.Type;
import com.neuronbit.javaparser.ast.CompilationUnit;
import com.neuronbit.javaparser.ast.Node;
import com.neuronbit.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.neuronbit.javaparser.resolution.types.ResolvedType;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

/**
 * The type Imports.
 */
public class Imports {
    private final Set<Type> imports;

    /**
     * Instantiates a new Imports.
     */
    public Imports() {
        imports = new HashSet<>(0);
    }

    /**
     * Of imports.
     *
     * @param type the type
     * @return the imports
     */
    public static Imports of(Type type) {
        Imports imports1 = new Imports();
        imports1.add(type);
        return imports1;
    }

    /**
     * Of imports.
     *
     * @param types the type
     * @return the imports
     */
    public static Imports of(HashSet<Type> types) {
        Imports imports1 = new Imports();
        types.forEach(imports1::add);
        return imports1;
    }

    /**
     * Of imports.
     *
     * @param type the type
     * @return the imports
     */
    public static Imports of(ResolvedType type) {
        Imports imports1 = new Imports();
        imports1.add(type);
        return imports1;
    }

    /**
     * Empty imports.
     *
     * @return the imports
     */
    public static Imports empty() {
        return new Imports();
    }

    /**
     * Add.
     *
     * @param type the type
     */
    public void add(Type type) {
        if (null == type) {
            return;
        }
        imports.add(type);
    }


    /**
     * Add.
     *
     * @param type the type
     */
    public void add(ResolvedType type) {
        if (null == type) {
            return;
        }
        SourceType sourceType = SourceType.of(type);
        if (!sourceType.isSimpleType()) {
            imports.add(sourceType);
        }
    }

    /**
     * Install.
     *
     * @param cu the cu
     */
    public void install(CompilationUnit cu) {
        if (null != cu) {
            imports.stream().filter(t -> !t.isSimpleType()).map(Type::getQualifiedName).forEach(cu::addImport);
        }
    }

    /**
     * Install.
     *
     * @param clazz the clazz
     */
    public void install(ClassOrInterfaceDeclaration clazz) {
        if (null == clazz) {
            return;
        }

        Optional<Node> parentNode = clazz.getParentNode();
        if (!parentNode.isPresent()) {
            return;
        }

        if (parentNode.get() instanceof CompilationUnit) {
            install(((CompilationUnit) parentNode.get()));
        }
    }

    /**
     * Add all.
     *
     * @param imports the imports
     */
    public void addAll(Imports imports) {
        if (null != imports) {
            this.imports.addAll(imports.imports);
        }
    }
}
